package com.yuexunit.web.servlet;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
import java.util.Timer;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.yuexunit.context.ThreadContext;
import com.yuexunit.finance.thread.EnterpriseSummaryTimeTask;
import com.yuexunit.finance.thread.FinanceThread;
import com.yuexunit.inject.ComponentFactory;
import com.yuexunit.util.DateUtil;
import com.yuexunit.util.StringUtil;
import com.yuexunit.util.ThreadUtil;
import com.yuexunit.web.annotation.AfterAction;
import com.yuexunit.web.annotation.BeforeAction;
import com.yuexunit.web.cfg.ActionServletRepository;

public class ActionServiceServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private static Logger LOG = LoggerFactory.getLogger(ActionServiceServlet.class);

	private static final String DEFAULT_CHARSET = "UTF-8";

	private static Set<Class<? extends ActionCommand>> ACTION_TYPES = ComponentFactory.findImplementors(ActionCommand.class);
	
	private static final long PERIOD_DAY = 24*60*60*1000;
	
	private static String randomUuid = "";
//	private static final long PERIOD_DAY = 1000;
	
	private FinanceThread financeThread;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		//防止重复提交
		req.setCharacterEncoding(DEFAULT_CHARSET);
		res.setHeader("Pragma","No-cache");
		res.setHeader("Cache-Control","no-cache");
		res.setDateHeader("Expires", 0); 
		if (StringUtil.isBlank(randomUuid) || !randomUuid.equals(req.getParameter("randomUuid")) || req.getParameter("randomUuid") == null) {
			randomUuid = req.getParameter("randomUuid");
			String uri = getUri(req);

			// 处理ActionServlet跳转
			HttpServlet servlet = ActionServletRepository.getMatchedServlet(uri);
			if (servlet != null) {
				servlet.service(req, res);
			} else {
				// 处理Action
				executeAction(uri, req, res);
			}
		}
	}
	
	public static void main(String[] args) {
		Timer timer = new Timer();     
		
		 Calendar calendar = Calendar.getInstance();
	        /*** 定制每日执行时间 ***/
	        calendar.set(Calendar.HOUR_OF_DAY, 10);
	        calendar.set(Calendar.MINUTE, 05);
	        calendar.set(Calendar.SECOND, 0);
	        Date date = calendar.getTime(); //第一次执行定时任务的时间
	        
        timer.schedule(new MyTask(), date, 2000);//在1秒后执行此任务,每次间隔2秒执行一次,如果传递一个Data参数,就可以在某个固定的时间执行这个任务.     
        while(true){//这个是用来停止此任务的,否则就一直循环执行此任务     
            try{     
                int in = System.in.read();    
                if(in == 's'){     
                    timer.cancel();//使用这个方法退出任务     
                    break;  
                }     
            } catch (IOException e){     
                // TODO Auto-generated catch block     
                e.printStackTrace();     
            }     
        }     
	}
	
	  static class MyTask extends java.util.TimerTask{      
	        public void run(){     
	            System.out.println("________");     
	        }     
	    }   

	@Override
	public void init() throws ServletException {
		//统计首页数据线程
		String str = null;  
        if (str == null && financeThread == null) {  
        	financeThread = new FinanceThread();  
        	financeThread.start(); // servlet 上下文初始化时启动 socket  
        }
        
        Timer timer = new Timer();
        
//        Calendar calendar = Calendar.getInstance();
//        /*** 定制每日执行时间 ***/
//        calendar.set(Calendar.HOUR_OF_DAY, 10);
//        calendar.set(Calendar.MINUTE, 11);
//        calendar.set(Calendar.SECOND, 0);
//        Date date = calendar.getTime(); //第一次执行定时任务的时间
        
        Long t = DateUtil.nextDay(DateUtil.thatDay(DateUtil.now())).getTime() - DateUtil.now().getTime();
        
        //每晚十二点执行
        timer.schedule(new EnterpriseSummaryTimeTask(), t, PERIOD_DAY);
	}

	/**
	 * @param req
	 * @return 请求路径
	 */
	private String getUri(HttpServletRequest req) {
		String uri = req.getRequestURI();
		String contextPath = req.getContextPath();
		if (uri.contains(contextPath)) {
			uri = uri.substring(contextPath.length());
		}

		return uri;
	}

	public void executeAction(String uri, HttpServletRequest request, HttpServletResponse response) {
		long startTime = System.currentTimeMillis();
		ActionContext actionContext = new ActionContext();
		try {
			actionContext.parse(uri, request.getParameterMap());
			if (!actionContext.isSuccess()) {
				throw actionContext.getCause();
			}

			actionContext.setStartTime(startTime);

			beforeExecuteAction(request, response, actionContext);

			actionContext.execute();
		} catch (Throwable th) {
			LOG.error("executeAction error: ", th);
			actionContext.setCause(th);
		} finally {
			afterExecuteAction(request, response, actionContext);

			ThreadContext.gc();
			ThreadUtil.gc();
		}
	}

	// 处理BeforeAction：比如：记录日志、参数验证、权限验证
	private void beforeExecuteAction(HttpServletRequest request, HttpServletResponse response, ActionContext actionContext) {
		for (Class<? extends ActionCommand> eachCommandType : ACTION_TYPES) {
			if (eachCommandType.isAnnotationPresent(BeforeAction.class)) {
				ActionCommand eachCommand = ComponentFactory.loadClass(eachCommandType);
				eachCommand.execute(request, response, actionContext);
			}
		}
	}

	// 处理AfterAction：比如：记录日志、输出结果之类
	private void afterExecuteAction(HttpServletRequest request, HttpServletResponse response, ActionContext actionContext) {
		for (Class<? extends ActionCommand> eachCommandType : ACTION_TYPES) {
			if (eachCommandType.isAnnotationPresent(AfterAction.class)) {
				try {
					ActionCommand eachCommand = ComponentFactory.loadClass(eachCommandType);
					eachCommand.execute(request, response, actionContext);
				} catch (Throwable ignore) {
					LOG.error("AfterAction error: ", ignore);
				}
			}
		}
	}
}
